home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Main_DevLib / LIBenv.c < prev    next >
Text File  |  1995-10-28  |  12KB  |  558 lines

  1. /*
  2.     devlib: environment module.
  3.  
  4.     source:  LIBenv.c
  5.     started: November 4, 1993.
  6.     version:
  7.         October 26, 1995
  8.             Changes made to support new Universal Headers.
  9.         January 7, 1994.
  10. */
  11.  
  12. #include <LIBlib.h>
  13.  
  14. #include <LIBenv.h>
  15. #include <LIBlist.h>
  16.  
  17.     /*
  18.         Only a dummy env_dump_stats is compiled unless THINK_C is #defined.
  19.     */
  20.     
  21.  
  22. #ifdef THINK_C
  23.     // Can't be used with Universal headers
  24.     // #include <LoMem.h>
  25.     
  26.     // From <LoMem.h>:  Warning: can't be used on a Power Mac.
  27.  
  28.     #define    Declare_LoMem(type, name, address)    type (name) : (address)
  29.     Declare_LoMem(THz, ApplZone, 0x2AA);
  30.  
  31. #endif
  32.  
  33. #if defined(THINK_C)
  34.  
  35.     #include <Errors.h>
  36.     #include <Memory.h>
  37.     #include <Resources.h>
  38.     #include <Types.h>
  39.  
  40. typedef struct code_struct code_info;
  41.  
  42. static struct code_struct {
  43.     TYPE_LIST(code_info);
  44.     int        code_ID;
  45.     long    code_tag;
  46.     long    code_addr;
  47.     long    code_checkSum;
  48. };
  49.  
  50. static code_info * old_code_info_list    = NULL;
  51. static code_info * new_code_info_list    = NULL;
  52.  
  53. /*
  54.     Declare internal routines.
  55. */
  56.  
  57. static code_info *    env_checkSum    (void);
  58. static void *        env_compare        (code_info * n1, code_info * n2);
  59. static void            env_heap1Stat    (char * name, int field1, long field2);
  60.  
  61. /*
  62.     Abort if the stack has overflowed.
  63. */
  64. void
  65. env_checkStack (void)
  66. {
  67.     if (env_stackPtr() <= env_stackLimit()) {
  68.         fatal(es("env_checkStack: stack overflow"));
  69.     }
  70. }
  71.  
  72. /*
  73.     Dump all Macintosh heap blocks.
  74. */
  75.  
  76. /*
  77.     Define the structure of heap block headers.
  78. */
  79. #define M_TAG_MASK        0xC0000000    /* Tag field of block_word1.    */
  80. #define M_RELOC_BIT        0x80000000    /* Relocatable bit.                */
  81. #define M_NRELOC_BIT    0x40000000    /* Non-relocatable bit.            */
  82. #define M_UNUSED_BITS    0x30000000    /* Unused bits.                    */
  83. #define M_CORRECT_MASK    0x0f000000    /* Size correction field.        */
  84. #define M_SIZE_MASK        0x00ffffff    /* Physical block size.            */
  85.  
  86. typedef struct m_blk_struct m_blk;
  87.  
  88. static struct m_blk_struct {
  89.     unsigned long    m_blk_word1;
  90.     unsigned long    m_blk_word2;
  91. };
  92.  
  93. /*
  94.     Define the structure of master pointers.
  95. */
  96.  
  97. /* See page II-25 */
  98. #define MP_LOCK        0x80000000        /* Locked bit.        */
  99. #define MP_PURGE    0x40000000        /* Purgeable bit.    */
  100. #define MP_RESOURCE    0x20000000        /* Resource bit.    */
  101. #define MP_ADDR        0x1fffffff        /* Address            */
  102.  
  103. /*
  104.     Checksum all 'CODE' blocks in the heap.
  105.     Abort if a problem is found.
  106. */
  107. void
  108. env_checkCode(void)
  109. {
  110.     register code_info * new_info;
  111.     register code_info * old_info;
  112.  
  113.     if (old_code_info_list == NULL) {
  114.         old_code_info_list= env_checkSum();
  115.     }
  116.     else {
  117.         new_code_info_list = env_checkSum();
  118.         for (old_info = old_code_info_list; old_info; old_info = old_info -> next) {
  119.             for (new_info = new_code_info_list; new_info; new_info = new_info -> next) {
  120.                 if (env_compare(new_info, old_info) != NULL) {
  121.                     break;
  122.                 }
  123.             }
  124.         }
  125.         old_code_info_list = new_code_info_list;
  126.     }
  127. }
  128.  
  129. /*
  130.     Compare the checksums of n and search_info.
  131.     Abort if they do not match.
  132. */
  133. static void *
  134. env_compare(code_info * n1, code_info * n2)
  135. {
  136.     FTAG("env_compare");
  137.  
  138.     if (n1 -> code_ID != n2 -> code_ID) {
  139.         return NULL;
  140.     }
  141.  
  142.     if (n1 -> code_checkSum != n2 -> code_checkSum) {
  143.         fatal(es("Checksum error: 'CODE' id: "); eint(n1 -> code_ID));
  144.     }
  145.     if (n1 -> code_tag != n2 -> code_tag) {
  146.         ;
  147.     }
  148.     if (n1 -> code_addr != n2 -> code_addr) {
  149.         ;
  150.     }
  151.     return n1;
  152. }
  153.  
  154. static code_info *
  155. env_checkSum (void)
  156. {
  157.     Zone *    z = ApplZone;
  158.     char *    zp = (char *) ApplZone;
  159.  
  160.     m_blk *    b;            /* Ptr to current block header.    */
  161.     char *    p;            /* char Ptr to block header.    */
  162.     m_blk *    b_last;        /* Ptr to zone trailer block.    */
  163.     char *    mp_addr;    /* Address of master pointer.    */
  164.  
  165.     register long val;
  166.     register long physical_size;
  167.  
  168.     /*
  169.         Step 1:  Create a list of all 'CODE' blocks.
  170.         'CODE' blocks are identified by their ID fields.
  171.     */
  172.  
  173.     b_last    = (m_blk *) z -> bkLim;
  174.     p  = (char *) &(z -> heapData);
  175.  
  176.     while (p < (char *) b_last) {
  177.  
  178.         /* Get the tag field. */
  179.         b = (m_blk *) p;
  180.         physical_size     = (b -> m_blk_word1) & M_SIZE_MASK;
  181.         val = (b -> m_blk_word1) & M_TAG_MASK;
  182.  
  183.         if (val & M_RELOC_BIT) {
  184.  
  185.             /* Relocatable block. */
  186.             mp_addr         = zp + b -> m_blk_word2;
  187.  
  188.             /* Get the master pointer. */
  189.             val = *( (long *) mp_addr);
  190.  
  191.             if (val & MP_RESOURCE) {
  192.  
  193.                 short    theID;
  194.                 Str255    name;
  195.                 ResType    theType;
  196.  
  197.                 /*
  198.                     Since the master pointer is in the reference list for a
  199.                     resource we can get the reference information.
  200.                 */
  201.                 GetResInfo( (Handle) mp_addr, &theID, &theType, (pstring) &name);
  202.  
  203.                 if (ResError() != resNotFound  && theType == 'CODE') {
  204.  
  205.                     /* Add the block to the code list. */
  206.  
  207.                 }
  208.             }
  209.         }
  210.  
  211.         p += physical_size;
  212.     }
  213.  
  214.     if (p != (char *) b_last) {
  215.         fatal(es("env_checkCode: Misalligned heap zone"));
  216.     }
  217.  
  218.     /* Step 2:  Compute and compare checksums. */
  219.  
  220.     /* Dummy for testing */
  221.     return NULL;
  222. }
  223.  
  224. /*
  225.     Calculate and print the heap statistics.
  226.  
  227.     Warning:  printing these statistics will likely change the heap!
  228. */
  229. void
  230. env_heapStat(void)
  231. {
  232.     Zone *    z = ApplZone;
  233.     char *    zp = (char *) ApplZone;
  234.  
  235.     m_blk *    b;            /* Ptr to current block header.    */
  236.     char *    p;            /* char Ptr to block header.    */
  237.     m_blk *    b_last;        /* Ptr to zone trailer block.    */
  238.     char *    mp_addr;    /* Address of master pointer.    */
  239.  
  240.     register long val;
  241.     register long physical_size;
  242.  
  243.     int    total        = 0;
  244.     int    tot_rel        = 0;
  245.     int    tot_nrel    = 0;
  246.     int tot_free    = 0;
  247.     int tot_lock    = 0;
  248.     int tot_purge    = 0;
  249.  
  250.     long tot_size    = 0L;
  251.     long rel_size    = 0L;
  252.     long nrel_size    = 0L;
  253.     long free_size    = 0L;
  254.     long lock_size    = 0L;
  255.     long purge_size    = 0L;
  256.  
  257.     b_last    = (m_blk *) z -> bkLim;
  258.     p  = (char *) &(z -> heapData);
  259.  
  260.     while (p < (char *) b_last) {
  261.  
  262.         b = (m_blk *) p;
  263.  
  264.         /* Calculate overall statistics. */
  265.         physical_size = (b -> m_blk_word1) & M_SIZE_MASK;
  266.         total++;
  267.         tot_size += physical_size;
  268.  
  269.         val = (b -> m_blk_word1) & M_TAG_MASK;
  270.         if (val == 0) {
  271.  
  272.             /* Free block. */
  273.             tot_free++;
  274.             free_size += physical_size;
  275.         }
  276.         else if (val & M_NRELOC_BIT  && !(val & M_RELOC_BIT)) {
  277.  
  278.             /* Non-relocatable block. */
  279.             tot_nrel++;
  280.             nrel_size += physical_size;
  281.         }
  282.         else if (val & M_RELOC_BIT && !(val& M_NRELOC_BIT)) {
  283.  
  284.             /* Relocatable block. */
  285.             tot_rel++;
  286.             rel_size    += physical_size;
  287.             mp_addr         = zp + b -> m_blk_word2;
  288.  
  289.             /* Get the master pointer. */
  290.             val = *( (long *) mp_addr);
  291.  
  292.             /* Print the lock, and purge fields. */
  293.             if (val & MP_LOCK) {
  294.                 tot_lock++;
  295.                 lock_size += physical_size;
  296.             }
  297.             else if (val & MP_PURGE) {
  298.                 tot_purge++;
  299.                 purge_size += physical_size;
  300.             }
  301.         }
  302.  
  303.         /* Point at the next block. */
  304.         p += physical_size;
  305.     }
  306.  
  307.     if (p != (char *) b_last) {
  308.         es("\nWarning:  misalligned heap zone.\n");
  309.     }
  310.  
  311.     es("Totals for application heap:\n\n");
  312.     eblanks(30);
  313.     es("Blocks    Logical Block Sizes\n");
  314.     env_heap1Stat("Free", tot_free, free_size);
  315.     env_heap1Stat("Nonrelocatable", tot_nrel, nrel_size);
  316.     env_heap1Stat("Relocatable", tot_rel, rel_size);
  317.     env_heap1Stat("  Locked", tot_lock, lock_size);
  318.     env_heap1Stat("  Purgeable and not locked", tot_purge, purge_size);
  319.     env_heap1Stat("Heap Totals", total, tot_size);
  320. }
  321.  
  322. static void
  323. env_heap1Stat(char * name, int field1, long field2)
  324. {
  325.     epads(name, -30); epadint(field1, 6);
  326.     eblanks(4); epadhex(field2, 8); es(" = "); epadlong(field2, 8);
  327.     enl();
  328. }
  329.  
  330. /*
  331.     dump the heap.
  332.  
  333.     Printing to the Sherlock window can cause the heap to move!
  334.     (sl_line_out calls DrawText, which can move the heap.)
  335.  
  336.     Thus, we must check z -> bkLim after every iteration.
  337. */
  338. void
  339. env_dumpHeap(void)
  340. {
  341.     Zone *    z = ApplZone;
  342.     char *    zp = (char *) ApplZone;
  343.  
  344.     m_blk *    b;            /* Ptr to current block header.    */
  345.     char *    p, *p2;        /* char Ptr to block header.    */
  346.     m_blk *    b_last;        /* Ptr to zone trailer block.    */
  347.     char *    mp_addr;    /* Address of master pointer.    */
  348.  
  349.     register long val;
  350.     register long physical_size;
  351.     register long logical_size;
  352.  
  353.     int    total        = 0;
  354.     int    tot_rel        = 0;
  355.     int    tot_nrel    = 0;
  356.     int tot_free    = 0;
  357.     int tot_lock    = 0;
  358.     int tot_purge    = 0;
  359.  
  360.     long tot_size    = 0L;
  361.     long rel_size    = 0L;
  362.     long nrel_size    = 0L;
  363.     long free_size    = 0L;
  364.     long lock_size    = 0L;
  365.     long purge_size    = 0L;
  366.  
  367.     b_last    = (m_blk *) z -> bkLim;
  368.     p  = (char *) &(z -> heapData);
  369.  
  370.     es("Displaying the Application Heap\n\n");
  371.     es("zone: "); eptr(z);
  372.     es(" first: "); eptr(p);
  373.     es(" last: "); eptr(b_last);
  374.     enl();
  375.     es("   Start    Length   Tag  Mstr Ptr  Lock Purge  Type   ID    File\n");
  376.  
  377.     while (p < (char *) b_last) {
  378.  
  379.         b = (m_blk *) p;
  380.  
  381.         /* Print the logical start and the logical length. */
  382.         physical_size     = (b -> m_blk_word1) & M_SIZE_MASK;
  383.         logical_size     = physical_size - sizeof(m_blk);
  384.  
  385.         total++;
  386.         tot_size        += physical_size;
  387.  
  388.         /* Print the tag field. */
  389.         val = (b -> m_blk_word1) & M_TAG_MASK;
  390.         if (val == 0) {
  391.  
  392.             /* Free block. */
  393.             tot_free++;
  394.             free_size += physical_size;
  395.  
  396.             /*
  397.                 Writing to the Sherlock window may create lots
  398.                 of free blocks, and the more we write the more are
  399.                 created.  Do not print free blocks!
  400.             */
  401.  
  402.         }
  403.         else if (val & M_NRELOC_BIT  && !(val & M_RELOC_BIT)) {
  404.  
  405.             /* Non-relocatable block. */
  406.             tot_nrel++;
  407.             nrel_size += physical_size;
  408.  
  409.             eblanks(2); eptr(p + sizeof(m_blk));
  410.             eblanks(1); elong(logical_size);
  411.             eblanks(3); es("N\n");
  412.         }
  413.         else if (val & M_RELOC_BIT && !(val& M_NRELOC_BIT)) {
  414.  
  415.             /* Relocatable block. */
  416.             tot_rel++;
  417.             rel_size    += physical_size;
  418.             mp_addr         = zp + b -> m_blk_word2;
  419.  
  420.             eblanks(2); eptr(p + sizeof(m_blk));
  421.             eblanks(1); elong(logical_size);
  422.             eblanks(3); es("R");
  423.             eblanks(3); eptr(mp_addr);
  424.  
  425.             /* Get the master pointer. */
  426.             val = *( (long *) mp_addr);
  427.  
  428.             /* Print the lock, and purge fields. */
  429.             if (val & MP_LOCK) {
  430.                 tot_lock++;
  431.                 lock_size += physical_size;
  432.             }
  433.             else if (val & MP_PURGE) {
  434.                 tot_purge++;
  435.                 purge_size += physical_size;
  436.             }
  437.  
  438.             eblanks(4); es((val & MP_LOCK)  ? "L" : " ");
  439.             eblanks(4); es((val & MP_PURGE) ? "P" : " ");
  440.  
  441.             if (val & MP_RESOURCE) {
  442.  
  443.                 short    theID;
  444.                 Str255    name;
  445.                 ResType    theType;
  446.                 char *    type = (char *) &theType;
  447.  
  448.                 /*
  449.                     Since the master pointer is in the reference list for a
  450.                     resource we can get the reference information.
  451.                 */
  452.                 GetResInfo( (Handle) mp_addr, &theID, &theType, (pstring) &name);
  453.  
  454.                 if (ResError() == resNotFound) {
  455.                     es("resNotFound");
  456.                 }
  457.                 else {
  458.  
  459.                     eblanks(4);
  460.                     echar(type[0]); echar(type[1]);
  461.                     echar(type[3]); echar(type[4]);
  462.  
  463.                     eblanks(3); epadhex(theID, 4);
  464.                     eblanks(1); epstring((char *) name);
  465.                 }
  466.             }
  467.  
  468.             /* Make sure the heap doesn't move till here. */
  469.             enl();
  470.         }
  471.         else {
  472.             es("BAD TYPE\n");
  473.         }
  474.  
  475.         /*
  476.             The newline will result in a line being output.
  477.             It may also result in the heap being moved.
  478.         */
  479.  
  480.         /*
  481.             Point at the next block beyond the current block.
  482.             This is *quite* tricky since the heap may have moved
  483.             since p was computed.
  484.         */
  485.  
  486.         p2 = (char *) &(z -> heapData);
  487.         while (p2 <= p && p2 < (char *) b_last) {
  488.             b    = (m_blk *) p2;
  489.             p2    += ((b -> m_blk_word1) & M_SIZE_MASK);
  490.         }
  491.         p = p2;
  492.     }
  493.  
  494.     if (p != (char *) b_last) {
  495.         es("\nWarning:  misalligned heap zone.\n");
  496.     }
  497.     else {
  498.         es("\nZone trailer: "); eptr(p); enl();
  499.     }
  500.  
  501.     es("\nTotals for application heap:\n");
  502.     eblanks(30);
  503.     es("Blocks  Logical Block Sizes\n");
  504.     env_heap1Stat("Free", tot_free, free_size);
  505.     env_heap1Stat("Nonrelocatable", tot_nrel, nrel_size);
  506.     env_heap1Stat("Relocatable", tot_rel, rel_size);
  507.     env_heap1Stat("  Locked", tot_lock, lock_size);
  508.     env_heap1Stat("  Purgeable and not locked", tot_purge, purge_size);
  509.     env_heap1Stat("Heap Totals", total, tot_size);
  510. }
  511.  
  512. char *
  513. env_a5 (void)
  514. {
  515.     register char * a5_p = 0;
  516.  
  517.     asm {
  518.         movea.l    a5, a5_p
  519.     }
  520.     return a5_p;
  521. }
  522.  
  523. char *
  524. env_stackLimit (void)
  525. {
  526.     return (char *) GetApplLimit();
  527. }
  528.  
  529. long
  530. env_stackMargin(void)
  531. {
  532.     return env_stackPtr() - env_stackLimit();
  533. }
  534.  
  535. char *
  536. env_stackPtr (void)
  537. {
  538.     register char * stack_p = 0;
  539.  
  540.     asm {
  541.         movea.l    sp, stack_p
  542.     }
  543.     return stack_p;
  544. }
  545.  
  546. #endif /* THINK_C */
  547.  
  548. /*
  549.     Only this dummy routine is defined if THINK_C is not #define'd.
  550. */
  551. void
  552. env_dump_stats(void)
  553. {
  554.     #if defined(THINK_C)
  555.         env_heapStat();
  556.     #endif
  557. }
  558.